#include "stdafx.h"

#include <cfloat>

#include "SHFEPublicHandler.h"
#include "Service/RequestIDGenerator.h"
#include "Utils/FastBlockQueue.h"
#include "Business/Market.h"
#include "Utils/Logger.h"

#pragma warning(disable:4100)

using namespace std;

SHFEPublicHandler::SHFEPublicHandler(Customer const& customer,
									 ContractCodes const& contractCodes,
									 FastBlockQueue& marketQueue)
:m_pMdApi(0),
m_customer(customer),
m_contractCodes(contractCodes),
m_marketQueue(marketQueue)
{
	for (UINT i = 0; i < m_contractCodes.size(); ++i)
	{
		Variety const& contract = m_contractCodes[i];
		m_contractIndexMap[contract.GetCode()] = i;
	}
}

void SHFEPublicHandler::OnFrontConnected()
{
	CShfeFtdcReqUserLoginField reqUserLogin; 
	strcpy_s(reqUserLogin.ParticipantID, m_customer.GetID());	
	strcpy_s(reqUserLogin.UserID, m_customer.GetShanghaiClientID());
	strcpy_s(reqUserLogin.Password,m_customer.GetPassword());
// 	strcpy_s(reqUserLogin.UserProductInfo, "sungard_v6p9");
	strcpy_s(reqUserLogin.UserProductInfo, "hundsun");

	int rtnLogin = m_pMdApi->ReqUserLogin(&reqUserLogin, 1);
	if (rtnLogin != 0)
	{
		LightLogger::Error(FT("SHFEPublicHandler ReqUserLogin failed,code[%d]",rtnLogin));
	}	
}

void SHFEPublicHandler::OnRspUserLogin(CShfeFtdcRspUserLoginField *pRspUserLogin, 
										CShfeFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
	if (!IsNull(pRspInfo) && pRspInfo->ErrorID != 0)
	{
#ifndef LOG4CPLUS_DISABLE_ERROR
		LightLogger::Error(FT("SHFEPublicHandler OnRspUserLogin failed,code[%d]",pRspInfo->ErrorID));
#endif
		return;
	}

#ifndef LOG4CPLUS_DISABLE_INFO
	LightLogger::Info("SHFEPublicHandler Login success");
#endif
}

void SHFEPublicHandler::OnRspError(CShfeFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
	if (IsNull(pRspInfo))
	{
#ifndef LOG4CPLUS_DISABLE_WARN
		LightLogger::Warn("SHFEPublicHandler OnRspError pRspInfo is null");
#endif
		return;
	}

#ifndef LOG4CPLUS_DISABLE_WARN
	LightLogger::Warn(FT("SHFEPublicHandler OnRspError code[%d],msg[%s]",pRspInfo->ErrorID,pRspInfo->ErrorMsg));
#endif
}

void SHFEPublicHandler::OnRspUserLogout(CShfeFtdcRspUserLogoutField *pRspUserLogout,
										CShfeFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
	if (IsNull(pRspUserLogout) || IsNull(pRspInfo))
	{
#ifndef LOG4CPLUS_DISABLE_WARN
		LightLogger::Warn("SHFEPublicHandler OnRspUserLogout pUserLogout or pRspInfo is null");
#endif
		return;
	}

	if (pRspInfo->ErrorID != 0)
	{
#ifndef LOG4CPLUS_DISABLE_WARN
		LightLogger::Warn(FT("SHFEPublicHandler OnRspUserLogout error code[%d], msg[%s]",pRspInfo->ErrorID,pRspInfo->ErrorMsg));
#endif
		return;
	}
#ifndef LOG4CPLUS_DISABLE_INFO
	LightLogger::Info("SHFEPublicHandler Logout success");
#endif
}

inline
static double Convert2Price(double price)
{
	double p = price;
	if (p == DBL_MAX)
	{
		p = 0;
	}
	return p;
}

inline
static Price Convert2Price(double price, int quantity)
{
	double p = Convert2Price(price);
	return Price(p,quantity);
}

bool IsUnnormalMarket(CShfeFtdcDepthMarketDataField* pDepthMarketData)
{
	const double UNNORMAL_PRICE = 10000000;
	bool ret = pDepthMarketData->BidPrice1 > UNNORMAL_PRICE || 
		pDepthMarketData->AskPrice1 > UNNORMAL_PRICE ||
		pDepthMarketData->UpperLimitPrice < 1 ||
		pDepthMarketData->UpperLimitPrice > UNNORMAL_PRICE ||
		pDepthMarketData->LowerLimitPrice < 1 ||
		pDepthMarketData->LowerLimitPrice > UNNORMAL_PRICE;

#ifndef LOG4CPLUS_DISABLE_DEBUG
// 	if (ret)
// 	{
// 		LightLogger::Debug(FT("Market[%s] unnormal:BidPrice1[%.2f],AskPrice1[%.2f],UpperLimitPrice[%.2f],LowerLimitPrice[%.2f]",
// 			pDepthMarketData->InstrumentID,
// 			pDepthMarketData->BidPrice1,
// 			pDepthMarketData->AskPrice1,
// 			pDepthMarketData->UpperLimitPrice,
// 			pDepthMarketData->LowerLimitPrice));
// 	}
#endif
	return ret;
}

void SHFEPublicHandler::OnRtnDepthMarketData(CShfeFtdcDepthMarketDataField *pDepthMarketData)
{
	if (IsNull(pDepthMarketData))
	{
#ifndef LOG4CPLUS_DISABLE_WARN
		LightLogger::Warn("SHFEPublicHandler OnRtnDepthMarketData pDepthMarketData is null");
#endif		
		return;
	}

	if (IsUnnormalMarket(pDepthMarketData))
	{
		return;
	}

	int contractIndex = GetContractIndex(pDepthMarketData->InstrumentID);
	if (contractIndex < 0)
	{
		return;
	}
	if (m_subscribeMarkets.find(contractIndex) == m_subscribeMarkets.end())
	{
		return;
	}
	int multiple = m_contractCodes[contractIndex].GetMultiple();

	Market market(CreateMarket(*pDepthMarketData, contractIndex, multiple));

	QueueItem item = {0};
	item.type = QueueItem::MARKET;
	memcpy(item.data,&market,sizeof(market));

	m_marketQueue.Push(item);
}

void SHFEPublicHandler::OnFrontDisconnected(int nReason)
{
#ifndef LOG4CPLUS_DISABLE_WARN
	LightLogger::Warn("SHFEPublicHandler FrontDisconnected!");
#endif
}

void SHFEPublicHandler::OnHeartBeatWarning(int nTimeLapse)
{
#ifndef LOG4CPLUS_DISABLE_WARN
	LightLogger::Warn("SHFEPublicHandler Market Beat warning");
#endif
}

Market SHFEPublicHandler::CreateMarket(CShfeFtdcDepthMarketDataField const& depthMarketData, 
									   int contractIndex,
									   int multiple)
{
	Prices buyPrices;
	buyPrices[0] = Convert2Price(depthMarketData.BidPrice1,depthMarketData.BidVolume1);
	buyPrices[1] = Convert2Price(depthMarketData.BidPrice2,depthMarketData.BidVolume2);
	buyPrices[2] = Convert2Price(depthMarketData.BidPrice3,depthMarketData.BidVolume3);
	buyPrices[3] = Convert2Price(depthMarketData.BidPrice4,depthMarketData.BidVolume4);
	buyPrices[4] = Convert2Price(depthMarketData.BidPrice5,depthMarketData.BidVolume5);


	Prices sellPrices;
	sellPrices[0] = Convert2Price(depthMarketData.AskPrice1,depthMarketData.AskVolume1);
	sellPrices[1] = Convert2Price(depthMarketData.AskPrice2,depthMarketData.AskVolume2);
	sellPrices[2] = Convert2Price(depthMarketData.AskPrice3,depthMarketData.AskVolume3);
	sellPrices[3] = Convert2Price(depthMarketData.AskPrice4,depthMarketData.AskVolume4);
	sellPrices[4] = Convert2Price(depthMarketData.AskPrice5,depthMarketData.AskVolume5);

	double upperLimit = Convert2Price(depthMarketData.UpperLimitPrice);
	double lowerLimit = Convert2Price(depthMarketData.LowerLimitPrice);
	Variety dummy_variety("UNDEFINED",-1,-1);
	CTime currentTime = CTime::GetCurrentTime();
	char hour[3] = {depthMarketData.UpdateTime[0],depthMarketData.UpdateTime[1]};
	char minute[3] = {depthMarketData.UpdateTime[3],depthMarketData.UpdateTime[4]};
	char second[3] = {depthMarketData.UpdateTime[6],depthMarketData.UpdateTime[7]};
	CTime time(currentTime.GetYear(),currentTime.GetMonth(),currentTime.GetDay(),
		atoi(hour),atoi(minute),atoi(second));
	Market market(contractIndex,dummy_variety,depthMarketData.LastPrice, depthMarketData.OpenInterest,
		buyPrices,sellPrices,upperLimit,lowerLimit,depthMarketData.PreSettlementPrice,time);
#ifdef DEBUG
	{
		static ofstream os("./market.csv");
		os << depthMarketData.InstrumentID << "," << depthMarketData.LastPrice << ",";
		os << depthMarketData.OpenInterest << "," << depthMarketData.UpdateTime<< "," << endl;
	}
#endif
	return market;
}

int SHFEPublicHandler::GetContractIndex( char const* instrumentID )
{
	map<string,int>::const_iterator iter = m_contractIndexMap.find(instrumentID);
	if (iter == m_contractIndexMap.end())
	{
// #ifndef LOG4CPLUS_DISABLE_DEBUG
// 		char msg[1024] = "";
// 		sprintf_s(msg,"InstrumentId[%s] can't find contractIndex",instrumentID);
// 		LightLogger::Debug(msg);
// #endif
		return -1;
	}
	return iter->second;
}

void SHFEPublicHandler::SubscribeMarket(char const* contract)
{
	int contractIndex = GetContractIndex(contract);
	m_subscribeMarkets[contractIndex] = contractIndex;
	LightLogger::Info(FT("subscribing [%s] public market", contract));
}

void SHFEPublicHandler::OnRspSubscribeTopic(CShfeFtdcDisseminationField *pDissemination, CShfeFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
}

void SHFEPublicHandler::OnRspQryTopic(CShfeFtdcDisseminationField *pDissemination, CShfeFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
}

void SHFEPublicHandler::OnPackageStart(int nTopicID, int nSequenceNo)
{
}

void SHFEPublicHandler::OnPackageEnd(int nTopicID, int nSequenceNo)
{
}

